package net.lcqf.http.exception;

import com.alibaba.fastjson.JSONException;
import net.lcqf.http.response.CommonResult;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletResponse;
import java.net.ConnectException;
import java.util.Objects;

/**
 * 全局异常捕捉
 * +----------------------------------------------------------------------
 * | Talk To [ 聊来改善地区金融服务环境，助力企业发展 ]
 * +----------------------------------------------------------------------
 * | Copyright (c) 2018-2024 聊来All rights reserved.
 * +----------------------------------------------------------------------
 * | Licensed ( <a href="http://www.apache.org/licenses/LICENSE-2.0">apache</a> )
 * +----------------------------------------------------------------------
 * | @Author: 贯彻己道的云 <18970881148@qq.com>
 * +----------------------------------------------------------------------
 * | DateTime: 2025/2/10 14:40
 * +----------------------------------------------------------------------
 */

@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 拦截JSON参数校验
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public CommonResult bindException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        return CommonResult.failed(ExceptionCodeEnum.FAILED, Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
    }

    /**
     * 拦截SQL异常
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BadSqlGrammarException.class)
    public CommonResult bindException(BadSqlGrammarException e) {
        return CommonResult.failed(ExceptionCodeEnum.FAILED, String.format("SQL异常：%s", e.getSQLException().getMessage()));
    }


    /**
     * 拦截url请求参数类型异常
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BindException.class)
    public CommonResult bindException(BindException e) {
        e.printStackTrace();
        return CommonResult.failed(ExceptionCodeEnum.FAILED, String.format("参数类型请求异常：%s", e.getFieldError()));
    }

    /**
     * 拦截SQL DML、DQL异常
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(DataIntegrityViolationException.class)
    public CommonResult bindException(DataIntegrityViolationException e) {
        return CommonResult.failed(ExceptionCodeEnum.FAILED, String.format("SQL DML、DQL异常：%s", e.getCause().getMessage()));
    }

    /**
     * 拦截JSON数据解析异常
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(JSONException.class)
    public CommonResult bindException(JSONException e) {
        return CommonResult.failed(ExceptionCodeEnum.FAILED, String.format("JSON数据解析异常：%s", e.getMessage()));
    }


    /**
     * 拦截系统自定义异常
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(TalkException.class)
    public CommonResult bindException(TalkException e) {
        if (e.getCode() == ExceptionCodeEnum.UNAUTHORIZED.getCode()) {
            return CommonResult.failed(ExceptionCodeEnum.UNAUTHORIZED, e.getMessage());
        } else {
            return CommonResult.failed(ExceptionCodeEnum.FAILED, e.getMessage());
        }
    }

    /**
     * 404 异常捕捉
     * @param response 响应体
     * @param e NoHandlerFoundException
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public CommonResult bindException(HttpServletResponse response, NoHandlerFoundException e) {
        response.setStatus(404);
        return CommonResult.failed(ExceptionCodeEnum.NOT_FOUND, ExceptionCodeEnum.NOT_FOUND.getMessage());
    }

    /**
     * Redis 异常捕捉
     * @param e RedisConnectionFailureException
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(RedisConnectionFailureException.class)
    public CommonResult bindException(RedisConnectionFailureException e) {
        return CommonResult.failed(ExceptionCodeEnum.FAILED, String.format("redis异常：%s", e.getMessage()));
    }

    /**
     * Multipart 异常捕捉
     * @param e FileUploadException
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MultipartException.class)
    public CommonResult bindException(MultipartException e) {
        return CommonResult.failed(ExceptionCodeEnum.FAILED, String.format("Multipart上传异常：%s", e.getMessage()));
    }


    /**
     * 第三方接口请求超时 异常捕捉
     * @param e FileUploadException
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(ConnectException.class)
    public CommonResult bindException(ConnectException e) {
        return CommonResult.failed(ExceptionCodeEnum.FAILED, String.format("请求超时：%s", e.getMessage()));
    }

    @ExceptionHandler(AccessDeniedException.class)
    @ResponseBody
    public <T> CommonResult<?> exceptionHandler(AccessDeniedException e) {
        // SpringSecurity的AccessDeniedException处理会在该异常捕捉之后，
        // 所以感官上是SpringSecurity配置的AccessDeniedHandler是失效的
        return CommonResult.failed(ExceptionCodeEnum.FORBIDDEN, e.getMessage());
    }

    /**
     * 捕捉其他异常
     * @param e 异常信息
     * @return T
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public <T> CommonResult<?> exceptionHandler(Exception e) {
        e.printStackTrace();

        // 未知错误
        return CommonResult.failed(ExceptionCodeEnum.ERROR, e.getMessage());
    }
}
